package edu.yngsxy.wxdemo.core.codegen;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.ReflectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class ObjectUtil {

    /**
     * 复制源对象属性到目标对象，空值和空字符串不复制
     * 对Map类型进行特殊处理，递归复制其内容
     */
    public static void copyPropertiesIgnoreEmpty(Object source, Object target) {
        if (Objects.isNull(source) || Objects.isNull(target)) {
            return;
        }

        BeanWrapper sourceWrapper = new BeanWrapperImpl(source);
        BeanWrapper targetWrapper = new BeanWrapperImpl(target);

        for (PropertyDescriptor sourcePd : sourceWrapper.getPropertyDescriptors()) {
            String propertyName = sourcePd.getName();

            if ("class".equals(propertyName)) continue;

            try {
                PropertyDescriptor targetPd = new PropertyDescriptor(propertyName, target.getClass());
                Method writeMethod = targetPd.getWriteMethod();
                if (writeMethod == null) continue;

                Object sourceValue = sourceWrapper.getPropertyValue(propertyName);
                Object targetValue = targetWrapper.getPropertyValue(propertyName);

                if (isValidValue(sourceValue)) {
                    if (sourceValue instanceof Map<?,?> sourceMap) {
                        handleMapCopy(sourceMap, targetValue, target, writeMethod);
                    } else {
                        writeMethod.invoke(target, sourceValue);
                    }
                }
            } catch (Exception e) {
                ReflectionUtils.handleReflectionException(e);
            }
        }
    }

    /**
     * 处理Map类型的属性复制
     */
    @SuppressWarnings("unchecked")
    private static void handleMapCopy(Map<?,?> sourceMap, Object targetValue, Object target, Method writeMethod) throws Exception {
        if (targetValue instanceof Map<?,?> targetMap) {
            copyMapEntries(sourceMap, (Map<Object, Object>) targetMap);
        } else {
            Map<?,?> newMap = createMapInstance((Class<? extends Map<?,?>>) sourceMap.getClass());
            writeMethod.invoke(target, newMap);
            copyMapEntries(sourceMap, (Map<Object, Object>) newMap);
        }
    }

    /**
     * 创建Map实例，使用Modifier判断抽象类
     */
    private static Map<?,?> createMapInstance(Class<? extends Map<?,?>> mapType) {
        try {
            // 使用Modifier类判断是否为接口或抽象类（修复isAbstract()方法不存在的问题）
            if (mapType.isInterface() || Modifier.isAbstract(mapType.getModifiers())) {
                return new HashMap<>();
            }

            Constructor<? extends Map<?,?>> constructor = mapType.getDeclaredConstructor();
            constructor.setAccessible(true);
            return constructor.newInstance();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Map类型" + mapType.getName() + "没有无参构造函数", e);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException("无法实例化Map对象: " + e.getMessage(), e);
        }
    }

    /**
     * 复制Map中的键值对，递归处理嵌套Map
     */
    @SuppressWarnings("unchecked")
    private static void copyMapEntries(Map<?,?> sourceMap, Map<Object, Object> targetMap) {
        sourceMap.forEach((key, value) -> {
            if (isValidValue(value)) {
                if (value instanceof Map<?,?> nestedMap) {
                    Map<Object, Object> targetNestedMap = (Map<Object, Object>) targetMap.get(key);
                    if (targetNestedMap == null) {
                        targetNestedMap = (Map<Object, Object>) createMapInstance((Class<? extends Map<?,?>>) nestedMap.getClass());
                        targetMap.put(key, targetNestedMap);
                    }
                    copyMapEntries(nestedMap, targetNestedMap);
                } else {
                    targetMap.put(key, value);
                }
            }
        });
    }

    /**
     * 验证属性值是否有效
     */
    private static boolean isValidValue(Object value) {
        return switch (value) {
            case null -> false;
            case String str -> !str.strip().isEmpty();
            case Map<?,?> map -> !map.isEmpty();
            default -> true;
        };
    }
}
